function stOut=lmjMinFmincon(xZero,estimopt,Y,funcModel,solveOpt,addSol,prpar,prss,stIn)
% stOut.LPosterior 
% stOut.mode 
% stOut.exitFlag
% stOut.iterations 
% stOut.Hessian
% stOut.time 
% stOut.info
% ======================================================================
% lmjMinFmincon.m 
%
% Formerly known as ESTIMA_FMINCON_CENTRAL.M
%
% Computes the log Posterior for the various cases defined by
% likelCentral.m
%
% Function underlying minization is identical to LMJ_POSTOPTIM.m and is
% included as a nested function. Only difference is that the parameter does 
% not go through the transformation matrix since the bounds are directly applied to the optimization 
% procedure using BOUNDS loaded from prior. 
% Hence X0 is an unstransformed starting value 
% format.  
%
% Input 
% ------
% Note:     Input PRPAR.LBND and PRPAR.UBND is truncated inside code 
% ESTIMOPT  Has all the settings for the optimization  
% Output 
% ------
% XMIN      in MIN  space for compatibility with GENSYSOUTPUT 
% XMODEL    in MODEL space  
% LPOSTMIN  stil *(-1) 
% Using OUTPUT, will display end message in a DIARY file created in the
% output subdirectory 
% 
% Alejandro Justiniano  January 11 2008 
% 1/13/09 Added LBND and UBND in priordens s.t. can work with the truncated
% BETA 
% 6/27/09 Added mixed frequency 
%         For faster speed could code a routine for each case 
%         FLAG_OK == 1 for solution to be valid 
% =======================================================================
clear x lpostd; 
if any(imag(xZero)~=0);error('Initial guess X0 cannot be imaginary');end
% Truncate bounds 
% ========================================================================
% Define the bounds for the optimization to ensure compatibility with
% INDMAT. Also check suggested starting point is within bounds, else adjust
% BOUNDS should NOT be truncated 
% ========================================================================
offset=1e-8; 
bounds=[prpar.lbnd(stIn.parPosEst)+offset prpar.ubnd(stIn.parPosEst)-offset]; 
check1=find(xZero < bounds(:,1));
check2=find(xZero > bounds(:,2)); 
if ~isempty(check1) 
    check1_disc=abs(xZero(check1)-prpar.lbnd(check1)); 
    if max(check1_disc) > 0.01;error('Starting value is below lower bound');end
    xZero(check1)=xZero(check1)+check1_disc+offset; 
end 
if ~isempty(check2) 
    check2_disc=abs(xZero(check2)-prpar.ubnd(check2)); 
    if max(check2_disc) > 0.01;
        dispaj('Positions ',check2(:),' above upper bound')
        error('Starting value is above upper bound')
    end
    xZero(check2)=xZero(check2)-check2_disc-offset;
end 
clear check* offset; 

stOut.LPosterior=inf;
stOut.mode=nan(length(xZero),1);
stOut.iterations=-1;
stOut.exitFlag=-10;
stOut.tiempo=0;
stOut.Hessian=nan(length(xZero));
stOut.info={'Problems at start'};


% ========================================================================
% Begin Optimization  
% ========================================================================
tic;
[stOut.mode,stOut.LPosterior,stOut.exitFlag,stOut.info,~,~,stOut.Hessian]=...
    fmincon(@lmj_postoptimsub,xZero,[],[],[],[],bounds(:,1),bounds(:,2),[],estimopt);
stOut.time=toc; 
stOut.iterations=stOut.info.iterations;
% ============================================
%           NESTED FUNCTION
% ============================================
    function lpostd=lmj_postoptimsub(x) 
        lpostd=1e20;
        stIn.parVec(stIn.parPosEst)=x;
        [lht,ssvec,flag_ok]= feval(addSol.funcLikel,x,stIn.parVec,stIn.parPosEst,funcModel,Y,stIn.trainVec,solveOpt,addSol);
        if flag_ok==0;
            return
        end        
        % 2. Prior for the parameters
        lpriord=sum(priordens(stIn.parVec,prpar.prior,prpar.alphap,prpar.betap,prpar.lbnd,prpar.ubnd));
        if isinf(abs(lpriord))==1;disp('Prior is INF');return;end        
        % 3. Prior for the SS 
        if ~isempty(stIn.ssPosEst)
            lpriord_ss = sum(priordens(ssvec(stIn.ssPosEst), prss.prior, prss.alphap, prss.betap, prss.lbnd, prss.ubnd));
        else
            lpriord_ss=0;
        end        
        lpostd=-(lpriord+lpriord_ss+lht); 
        %disp(['LPOSTD=',num2str(lpostd)]); 
    end
end